﻿using System;
using System.Diagnostics;

namespace RoMBot.MemoryLib
{
    /// <summary>
    /// Contains static methods for finding and opening a process.
    /// </summary>
    public static class SProcess
    {
        /// <summary>
        /// Open process for external manipulation.
        /// </summary>
        /// <param name="dwProcessId">Process ID of external process to be opened.</param>
        /// <param name="dwAccessRights">Required access to external process.</param>
        /// <returns>Returns IntPtr.Zero on failure, non-zero on success.</returns>
        public static IntPtr OpenProcess( int dwProcessId, uint dwAccessRights )
        {
            return Imports.OpenProcess( dwAccessRights, false, dwProcessId );
        }

        /// <summary>
        /// Open process for external manipulation.  PROCESS_ALL_ACCESS will automatically be granted and handle will not be inherited.
        /// </summary>
        /// <param name="dwProcessId">The unique process ID of the external program.</param>
        /// <returns>Returns IntPtr.Zero on failure, non-zero on success.</returns>
        public static IntPtr OpenProcess( int dwProcessId )
        {
            return OpenProcess( dwProcessId, AccessRights.PROCESS_ALL_ACCESS );
        }

        /// <summary>
        /// Open process for external manipulation.
        /// </summary>
        /// <param name="hWnd">Handle to the main window of the process to be opened.</param>
        /// <param name="dwAccessRights">Required access to external process.</param>
        /// <returns>Returns IntPtr.Zero on failure, non-zero on success.</returns>
        public static IntPtr OpenProcess( IntPtr hWnd, uint dwAccessRights )
        {
            return OpenProcess( GetProcessFromWindow( hWnd ), dwAccessRights );
        }

        /// <summary>
        /// Open process for external manipulation.  PROCESS_ALL_ACCESS will automatically be granted and handle will not be inherited.
        /// </summary>
        /// <param name="hWnd">Main window handle of the process.</param>
        /// <returns>Returns IntPtr.Zero on failure, non-zero on success.</returns>
        public static IntPtr OpenProcess( IntPtr hWnd )
        {
            //get process id, then open with PROCESS_ALL_ACCESS rights
            return OpenProcess( GetProcessFromWindow( hWnd ), AccessRights.PROCESS_ALL_ACCESS );
        }

        /// <summary>
        /// Gets the process ID of the process that created the supplied window handle.
        /// </summary>
        /// <param name="hWnd">Handle to the main window of the process in question.</param>
        /// <returns>Returns non-zero on success, zero on failure.</returns>
        public static int GetProcessFromWindow( IntPtr hWnd )
        {
            int dwProcessId;
            Imports.GetWindowThreadProcessId( hWnd, out dwProcessId );
            return dwProcessId;
        }

        /// <summary>
        /// Gets the process ID of the process that created the first window to match the given window title.
        /// </summary>
        /// <param name="windowTitle">Title of the main window whose process id we want.</param>
        /// <returns>Returns non-zero on success, zero on failure.</returns>
        public static int GetProcessFromWindowTitle( string windowTitle )
        {
            var hWnd = SWindow.FindWindow( null, windowTitle );
            return hWnd == IntPtr.Zero ? 0 : GetProcessFromWindow( hWnd );
        }

        /// <summary>
        /// Returns an array of process ids of processes that match given window title.
        /// </summary>
        /// <param name="windowTitle">Title of windows to match.</param>
        /// <returns>Returns null on failure, array of integers populated with process ids on success.</returns>
        public static int[] GetProcessesFromWindowTitle( string windowTitle )
        {
            var hWnds = SWindow.FindWindows( null, windowTitle );
            if ( hWnds == null || hWnds.Length == 0 )
                return null;

            var ret = new int[ hWnds.Length ];

            for ( var i = 0; i < ret.Length; i++ )
                ret[ i ] = GetProcessFromWindow( hWnds[ i ] );

            return ret;
        }

        /// <summary>
        /// Gets the process ID of the process that created the first window to match the given window title.
        /// </summary>
        /// <param name="classname">Classname of the main window whose process id we want.</param>
        /// <returns>Returns non-zero on success, zero on failure.</returns>
        public static int GetProcessFromClassname( string classname )
        {
            IntPtr hWnd = SWindow.FindWindow( classname, null );
            if ( hWnd == IntPtr.Zero )
                return 0;

            return GetProcessFromWindow( hWnd );
        }

        /// <summary>
        /// Returns an array of process ids of processes that match given window title.
        /// </summary>
        /// <param name="classname">Classname of windows to match.</param>
        /// <returns>Returns null on failure, array of integers populated with process ids on success.</returns>
        public static int[] GetProcessesFromClassname( string classname )
        {
            var hWnds = SWindow.FindWindows( classname, null );
            if ( hWnds == null || hWnds.Length == 0 )
                return null;

            var ret = new int[ hWnds.Length ];

            for ( var i = 0; i < ret.Length; i++ )
                ret[ i ] = GetProcessFromWindow( hWnds[ i ] );

            return ret;
        }

        /// <summary>
        /// Gets the process id of the process whose executable name matches that which is supplied.
        /// </summary>
        /// <param name="processName">Name of the executable to match.</param>
        /// <returns>Returns non-zero on success, zero on failure.</returns>
        public static int GetProcessFromProcessName( string processName )
        {
            if ( processName.EndsWith( ".exe" ) )
                processName = processName.Remove( processName.Length - 4, 4 );

            var procs = Process.GetProcessesByName( processName );
            return procs.Length == 0 ? 0 : procs[ 0 ].Id;
        }
    }
}